
static TRef recff_check_ud(jit_State *J, TRef ud, int32_t udtype)
{
  TRef tr;
  
  if (!tref_isudata(ud))
    lj_trace_err(J, LJ_TRERR_BADTYPE);
  tr = emitir(IRT(IR_FLOAD, IRT_U8), ud, IRFL_UDATA_UDTYPE);
  emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, udtype));

  return ud;
  //fp = emitir(IRT(IR_FLOAD, IRT_LIGHTUD), ud, IRFL_UDATA_FILE);
  //emitir(IRTG(IR_NE, IRT_LIGHTUD), fp, lj_ir_knull(J, IRT_LIGHTUD));
}

static void LJ_FASTCALL recff_serialize_putint(jit_State *J, RecordFFData *rd)
{
  TRef ctx = recff_check_ud(J, J->base[0], UDTYPE_SERIALIZE_CONTEXT);
  TRef ctxp = emitir(IRT(IR_FREF, IRT_PTR), ctx, IRFL_UDATA_BEGIN);
  TRef x = lj_ir_toint(J, J->base[1]);
  lj_ir_call(J, rd->data, ctxp, x);
  rd->nres = 0;
}

static void LJ_FASTCALL recff_serialize_putend(jit_State *J, RecordFFData *rd)
{
  TRef ctx = recff_check_ud(J, J->base[0], UDTYPE_SERIALIZE_CONTEXT);
  TRef ctxp = emitir(IRT(IR_FREF, IRT_PTR), ctx, IRFL_UDATA_BEGIN);
  lj_ir_call(J, rd->data, ctxp);
  rd->nres = 0;
}



static void LJ_FASTCALL recff_serialize_getint(jit_State *J, RecordFFData *rd)
{
  TRef ctx = recff_check_ud(J, J->base[0], UDTYPE_SERIALIZE_CONTEXT);
  TRef ctxp = emitir(IRT(IR_FREF, IRT_PTR), ctx, IRFL_UDATA_BEGIN);
  J->base[0] = lj_ir_call(J, IRCALL_lj_serialize_getint, ctxp);
}

static void LJ_FASTCALL recff_serialize_firstmsg(jit_State *J, RecordFFData *rd)
{
  TRef ctx = recff_check_ud(J, J->base[0], UDTYPE_SERIALIZE_CONTEXT);
  TRef ctxp = emitir(IRT(IR_FREF, IRT_PTR), ctx, IRFL_UDATA_BEGIN);
  J->base[0] = lj_ir_call(J, IRCALL_lj_serialize_firstmsg, ctxp);
}

static void LJ_FASTCALL recff_serialize_nextmsg(jit_State *J, RecordFFData *rd)
{
  TRef ctx = recff_check_ud(J, J->base[0], UDTYPE_SERIALIZE_CONTEXT);
  TRef ctxp = emitir(IRT(IR_FREF, IRT_PTR), ctx, IRFL_UDATA_BEGIN);
  J->base[0] = lj_ir_call(J, IRCALL_lj_serialize_nextmsg, ctxp);
}

/* Flip */

static void LJ_FASTCALL recff_flip_sprite_dd(jit_State *J, RecordFFData *rd)
{
  TRef self = recff_check_ud(J, J->base[0], UDTYPE_FLIP_SPRITE);
  TRef selfp = emitir(IRT(IR_FREF, IRT_PTR), self, IRFL_UDATA_BEGIN);
  TRef a = lj_ir_tonum(J, J->base[1]);
  TRef b = lj_ir_tonum(J, J->base[2]);
  lj_ir_call(J, rd->data, selfp, a, b);
  rd->nres = 0;
}

static void LJ_FASTCALL recff_flip_sprite_ddd(jit_State *J, RecordFFData *rd)
{
  TRef self = recff_check_ud(J, J->base[0], UDTYPE_FLIP_SPRITE);
  TRef selfp = emitir(IRT(IR_FREF, IRT_PTR), self, IRFL_UDATA_BEGIN);
  TRef a = lj_ir_tonum(J, J->base[1]);
  TRef b = lj_ir_tonum(J, J->base[2]);
  TRef c = lj_ir_tonum(J, J->base[3]);
  lj_ir_call(J, rd->data, selfp, a, b, c);
  rd->nres = 0;
}

static void LJ_FASTCALL recff_flip_sprite_dddd(jit_State *J, RecordFFData *rd)
{
  TRef self = recff_check_ud(J, J->base[0], UDTYPE_FLIP_SPRITE);
  TRef selfp = emitir(IRT(IR_FREF, IRT_LIGHTUD), self, IRFL_UDATA_BEGIN);
  TRef a = lj_ir_tonum(J, J->base[1]);
  TRef b = lj_ir_tonum(J, J->base[2]);
  TRef c = lj_ir_tonum(J, J->base[3]);
  if(J->base[4])
    lj_trace_err(J, LJ_TRERR_BADTYPE);
  lj_ir_call(J, rd->data, selfp, a, b, c);
  rd->nres = 0;
}

static void LJ_FASTCALL recff_flip_text(jit_State *J, RecordFFData *rd)
{
  TRef self = recff_check_ud(J, J->base[0], UDTYPE_FLIP_FONT);
  TRef selfp = emitir(IRT(IR_FREF, IRT_PTR), self, IRFL_UDATA_BEGIN);
  TRef str = lj_ir_tostr(J, J->base[1]);
  TRef x = lj_ir_tonum(J, J->base[2]);
  TRef y = lj_ir_tonum(J, J->base[3]);
  TRef zero = lj_ir_kint(J, 0);
  TRef strp = emitir(IRT(IR_STRREF, IRT_PTR), str, zero);
  lj_ir_call(J, rd->data, selfp, strp, x, y);
  rd->nres = 0;
}

static void LJ_FASTCALL recff_flip_line(jit_State *J, RecordFFData *rd)
{
  TRef x1 = lj_ir_tonum(J, J->base[0]);
  TRef y1 = lj_ir_tonum(J, J->base[1]);
  TRef x2 = lj_ir_tonum(J, J->base[2]);
  TRef y2 = lj_ir_tonum(J, J->base[3]);
  lj_ir_call(J, rd->data, x1, y1, x2, y2);
  rd->nres = 0;
}

static void LJ_FASTCALL recff_flip_vertex(jit_State *J, RecordFFData *rd)
{
  TRef x1 = lj_ir_tonum(J, J->base[0]);
  TRef y1 = lj_ir_tonum(J, J->base[1]);
  lj_ir_call(J, rd->data, x1, y1);
  rd->nres = 0;
}

static void LJ_FASTCALL recff_box2d_core_body_orientation(jit_State *J, RecordFFData *rd)
{
	TRef world = recff_check_ud(J, J->base[0], UDTYPE_BOX2D_WORLD);
	TRef worldp = emitir(IRT(IR_FREF, IRT_PTR), world, IRFL_UDATA_BEGIN);
	TRef id = lj_ir_toint(J, J->base[1]);
	TRef body = lj_ir_call(J, IRCALL_lj_box2d_get_body, worldp, id);
	emitir(IRTG(IR_NE, IRT_LIGHTUD), body, lj_ir_knull(J, IRT_LIGHTUD));

	J->base[0] = lj_ir_call(J, IRCALL_lj_box2d_get_body_x, body);
	J->base[1] = lj_ir_call(J, IRCALL_lj_box2d_get_body_y, body);
	J->base[2] = lj_ir_call(J, IRCALL_lj_box2d_get_body_ang, body);
	rd->nres = 3;
}

/* math */

static void LJ_FASTCALL recff_random_method_gen(jit_State *J, RecordFFData *rd)
{
  TRef rand = recff_check_ud(J, J->base[0], UDTYPE_RANDOM);
  TRef randp = emitir(IRT(IR_FREF, IRT_PTR), rand, IRFL_UDATA_BEGIN);

  TRef tr, one;
  tr = lj_ir_call(J, IRCALL_lj_math_random_step, randp);
  one = lj_ir_knum_one(J);
  tr = emitir(IRTN(IR_SUB), tr, one);
  if (J->base[1]) {
    TRef tr1 = lj_ir_tonum(J, J->base[1]);
    if (J->base[2]) {  /* d = floor(d*(r2-r1+1.0)) + r1 */
      TRef tr2 = lj_ir_tonum(J, J->base[2]);
      tr2 = emitir(IRTN(IR_SUB), tr2, tr1);
      tr2 = emitir(IRTN(IR_ADD), tr2, one);
      tr = emitir(IRTN(IR_MUL), tr, tr2);
      tr = emitir(IRTN(IR_FPMATH), tr, IRFPM_FLOOR);
      tr = emitir(IRTN(IR_ADD), tr, tr1);
    } else {  /* d = floor(d*r1) + 1.0 */
      tr = emitir(IRTN(IR_MUL), tr, tr1);
      tr = emitir(IRTN(IR_FPMATH), tr, IRFPM_FLOOR);
      tr = emitir(IRTN(IR_ADD), tr, one);
    }
  }
  J->base[0] = tr;
  UNUSED(rd);
}

static void LJ_FASTCALL recff_filesystem_reader_method_get(jit_State *J, RecordFFData *rd)
{
	TRef reader = recff_check_ud(J, J->base[0], UDTYPE_STREAMS_READER);
	TRef readerp = emitir(IRT(IR_FREF, IRT_PTR), reader, IRFL_UDATA_BEGIN);

	TRef res = lj_ir_call(J, IRCALL_lj_filesystem_reader_get, readerp);
	emitir(IRTG(IR_GE, IRT_INT), res, lj_ir_kint(J, 0));

	J->base[0] = res;
}

static void LJ_FASTCALL recff_filesystem_writer_method_put(jit_State *J, RecordFFData *rd)
{
	TRef writer = recff_check_ud(J, J->base[0], UDTYPE_STREAMS_WRITER);
	TRef writerp = emitir(IRT(IR_FREF, IRT_PTR), writer, IRFL_UDATA_BEGIN);
	TRef b = lj_ir_toint(J, J->base[1]);

	TRef res = lj_ir_call(J, IRCALL_lj_filesystem_writer_put, writerp, b);
	
	J->base[0] = res;
}